package com.erbao.interview;

import java.util.LinkedList;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 固定容量的同步容器，拥有方法put和get，以及getCount
 * 2个生产者 10个消费者
 * @author CaoBaoYin
 * @since 2022/2/27 21:13
 */
public class ConsumerProducerV2 {

    public static void main(String[] args) {
        final FixedCapacity<String> fixedCapacity = new FixedCapacity<>(10);

        Runnable consumer = () ->{
            for (int i = 0; i < 5; i++) {
                System.out.println(Thread.currentThread().getName()+" get "+ fixedCapacity.get());
            }
        };

        Runnable producer = () -> {
            for (int i = 0; i < 25; i++) {
                fixedCapacity.put(Thread.currentThread().getName() + "_" + i);
            }
        };

        for (int i = 0; i < 2; i++) {
            new Thread(producer, "p"+i).start();
        }

        for (int i = 0; i < 10; i++) {
            new Thread(consumer, "c"+i).start();
        }
    }


}


class FixedCapacityV2<E> {
    private LinkedList<E> list;
    private int limit;
    private ReentrantLock lock = new ReentrantLock();
    // condition 的本质就是不同的等待队列
    private Condition producer = lock.newCondition();
    private Condition consumer = lock.newCondition();

    public FixedCapacityV2(int limit) {
        this.limit = limit;
        list = new LinkedList<>();
    }

    public void put (E e) {

        try {
            lock.lock();
            while (list.size() == this.limit) {
                System.out.println("capacity is full");
                producer.await();
            }
            list.add(e);
            consumer.signalAll();
        } catch (Exception ex) {
            ex.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public synchronized E get () {
        E e = null;
        try {
            lock.lock();
            while (list.size() == 0) {
                System.out.println("capacity is empty");
                consumer.await();
            }
            e = list.removeFirst();
            producer.signalAll();
        } catch (Exception ex) {
            ex.printStackTrace();
        } finally {
            lock.unlock();
        }

        return e;
    }

    public int getCount () {
        return list.size();
    }
}
